<?php
/*time:2017/07/23
 *微信公众号授权
 *@author zgz
 * PHP设计模式:工厂模式
 */
namespace app\weixin\controller;
use think\cache\driver\Redis;
//定义规则
interface Wx
{
    //初始化
    function  init ();
}
class Wx_userInfo implements Wx{
    private  $appId ;
    private  $appSecret;
    private  $code;
    private  $openid;
    private  $access_token;
    private  static $_instance;
    /**
     *
     * php初始化设置公众号appid和公众号appSecret,为初始化对象时调用
     * @param string  $appId
     * @param string  $appSecret
     */
    public function __construct($appId, $appSecret,$code) {
        $this->redis = new Redis();
        $this->appId = $appId;
        $this->appSecret = $appSecret;
        $this->code = $code;
    }


    //对象被调用后，释放内存
    public function __destruct(){

    }

    //默认生成对象
    public static function getInstance($appId, $appSecret,$code)
    {
        if(! (self::$_instance instanceof self) )
        {
            self::$_instance = new self($appId, $appSecret,$code);
        }
        return self::$_instance;
    }

    public  function  init (){
        //第一步:通过code换取网页授权access_token,获取openid
        $resule = $this->getAccess_token();
        if($resule==false){
            return false;
        }
        //获取用户信息
        return $this->geiUserInfo();
    }

    //通过code换取网页授权access_token,获取openid
    function  getAccess_token(){
        //请求时，每个code都是不一样的，每个code对应每个access_token。每个access_token有两小时的有效期
        $appid=$this->appId;
        $secret=$this->appSecret;
        $code=$this->code;
        //$session_code_access_token = Cache::get($code);
        $session_code_access_token = $this->redis->get($code);
        if($session_code_access_token && !empty($session_code_access_token)){
            $session_code_access_token = explode(',',$session_code_access_token);
            $this->access_token = $session_code_access_token[0];
            $this->openid = $session_code_access_token[1];
            return true;
        }
        else{
            $url="https://api.weixin.qq.com/sns/oauth2/access_token?appid={$appid}&secret={$secret}&code={$code}&grant_type=authorization_code";
            $callBack =json_decode($this->https_request($url));
            if(isset($callBack->{'errcode'})){
                file_put_contents( "error.txt", PHP_EOL.PHP_EOL, FILE_APPEND);
                file_put_contents( "error.txt", '用户信息获取错误:'.PHP_EOL, FILE_APPEND);
                file_put_contents( "error.txt", json_encode($callBack).PHP_EOL, FILE_APPEND);
                return false;
            }
            // 根据openid和access_token查询用户信息
            $this->access_token = $callBack -> {'access_token'};
            $this->openid = $callBack -> {'openid'};
            //Cache::set($code,$this->access_token.",".$this->openid,7100);
            $this->redis->set($code,$this->access_token.",".$this->openid,7100);
            return true;
        }
    }

    //获取用户信息
    function  geiUserInfo(){
        $access_token=$this->access_token;
        $openid=$this->openid;
        $url="https://api.weixin.qq.com/sns/userinfo?access_token=$access_token&openid=$openid&lang=en";
        $callBack =  json_decode($this->https_get($url),true);
        /*获取微信用户信息:*/
        try{
            /*
            if(isset($callBack->{'nickname'})){
                $nickname = $callBack->{'nickname'};//获取用户名
                $sex = $callBack->{'sex'};//获取性别
                $province =$callBack->{'province'};//获取省份
                $city = $callBack->{'city'};//获取城市
                $country = $callBack->{'country'};//获取国家
                $headimgurl = $callBack->{'headimgurl'};//获取头像
                $privilege =$callBack->{'privilege'};//获取用户特权信息
                $userinfo=array("openid"=>$openid,"nickname"=>$nickname,"sex"=>$sex,"province"=>$province,"city"=>$city,"country"=>$country,"headimgurl"=>$headimgurl);
            }
            */
            if(isset($callBack['nickname'])){
                $userinfo = $callBack ;
                unset($userinfo['language']);
                unset($userinfo['privilege']);
            }
            //$userinfo['nickname'] = json_encode($userinfo['nickname']);
            return $userinfo;
        }
        catch(Exception $e){
            return false;
        };
    }

    /**
     * 发送HTTP请求方法
     * @param  string $url    请求URL
     * @param  array  $data   请求参数
     * @param  string $ref
     * @return array  $data   响应数据
     */
    function https_request($url) {
        $curl = curl_init(); // 启动一个CURL会话
        $data = "";
        $ref ="";
        $this_header = array(
            "content-type: application/x-www-form-urlencoded; 
         charset=UTF-8"
        );
        curl_setopt($curl, CURLOPT_HTTPHEADER, $this_header);
        $url = urldecode($url);
        curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查
        curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览器
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转
        curl_setopt($curl, CURLOPT_REFERER, $ref);
        curl_setopt($curl, CURLOPT_POST, 1); // 发送一个常规的Post请求
        curl_setopt($curl, CURLOPT_ENCODING, 'gzip,deflate');
        curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循环
        curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回
        //curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data)); // Post提交的数据包
        //curl_setopt($curl, CURLOPT_COOKIEFILE, $GLOBALS ['cookie_file']); // 读取上面所储存的Cookie信息
        //curl_setopt($curl, CURLOPT_COOKIEJAR, $GLOBALS['cookie_file']); // 存放Cookie信息的文件名称
        //curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 1); // 从证书中检查SSL加密算法是否存在
        $tmpInfo = curl_exec($curl); // 执行操作
        if (curl_errno($curl)) {
            echo 'Errno' . curl_error($curl);
        }
        curl_close($curl); // 关闭CURL会话
        return $tmpInfo; // 返回数据
    }
    function  https_get($url){
        $ch = curl_init();                         //初始化
        //不检验https
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        curl_setopt($ch, CURLOPT_URL,$url);           //GET方法抓取URL地址
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //以文件流方式输出
        $output=curl_exec($ch);                           //执行，将文件保存到变量$a
        curl_close($ch);
        return $output ;
    }

}